#define htu20_Variable

#include "userDef.h"

#ifdef HTU20_SENSOR
void IIC_HT_Init(void)
{
    SDA_IO_SET_OUTPUT;
    SCK_IO_SET_OUTPUT;

    SDA_SET_HIGH_LEVEL;
    SCK_SET_HIGH_LEVEL;
}

void delay_us(U8 i)
{
    U8 j = 10;

    while (i)
    {
        j = 10;

        while (j)
        {
            __NOP();
            j--;
        }

        i--;
    }
}

void IIC_HT_Start(void)
{
    SDA_IO_SET_OUTPUT;

    SDA_SET_HIGH_LEVEL;
    SCK_SET_HIGH_LEVEL;

    delay_us(4);

    SDA_SET_LOW_LEVEL;

    delay_us(4);

    SCK_SET_LOW_LEVEL;
}

void IIC_HT_Stop(void)
{
    SDA_IO_SET_OUTPUT;

    SCK_SET_LOW_LEVEL;
    SDA_SET_LOW_LEVEL;

    delay_us(4);

    SCK_SET_HIGH_LEVEL;

    delay_us(4);

    SDA_SET_HIGH_LEVEL;
}

U8 IIC_HT_Write_Byte(U8 Write_Byte) // Send byte
{
    U8 i, error = 0;
    U16 ucErrTime = 0;

    SDA_IO_SET_OUTPUT;

    SCK_SET_LOW_LEVEL;

    for (i = 0; i < 8; i++)
    {
        if (Write_Byte & 0x80)
        {
            SDA_SET_HIGH_LEVEL;
        }
        else
        {
            SDA_SET_LOW_LEVEL;
        }

        delay_us(4);

        SCK_SET_HIGH_LEVEL;

        delay_us(4);

        SCK_SET_LOW_LEVEL;

        delay_us(4);

        Write_Byte <<= 1;
    }

    delay_us(4);

    SDA_SET_HIGH_LEVEL;

    SDA_IO_SET_INPUT;

    delay_us(4);

    SCK_SET_HIGH_LEVEL;

    delay_us(4);

    while (IO_SDA_HT)
    {
        ucErrTime++;

        if (ucErrTime > 250)
        {
            error = HTU20NACK;

            IIC_HT_Stop();

            return error;
        }
    }

    if (ucErrTime < 250)
    {
        error = HTU20ACK;
    }

    delay_us(4);

    SCK_SET_LOW_LEVEL;

    delay_us(4);

    return error;
}

void IIC_HT_Ack(void)
{
    SCK_SET_LOW_LEVEL;

    SDA_IO_SET_OUTPUT;

    SDA_SET_LOW_LEVEL;

    delay_us(4);

    SCK_SET_HIGH_LEVEL;

    delay_us(4);

    SCK_SET_LOW_LEVEL;
}

void IIC_HT_NAck(void)
{
    SCK_SET_LOW_LEVEL;

    SDA_IO_SET_OUTPUT;

    SDA_SET_HIGH_LEVEL;

    delay_us(4);

    SCK_SET_HIGH_LEVEL;

    delay_us(4);

    SCK_SET_LOW_LEVEL;
}

U8 IIC_HT_Read_Byte(U8 AckValue) // receive byte
{
    U8 i, RDByte = 0;

    SDA_SET_HIGH_LEVEL;

    SDA_IO_SET_INPUT;

    SCK_SET_LOW_LEVEL;

    for (i = 0; i < 8; i++)
    {
        SCK_SET_LOW_LEVEL;

        delay_us(4);

        SCK_SET_HIGH_LEVEL;

        delay_us(4);

        RDByte <<= 1;

        if (IO_SDA_HT)
        {
            RDByte |= 0x01;
        }
        else
        {
            RDByte &= 0xfe;
        }

        delay_us(4);
    }

    if (AckValue == HTU20NACK)
    {
        IIC_HT_NAck();
    }
    else
    {
        IIC_HT_Ack();
    }

    return RDByte;
}

void SoftReset(void)
{
    U8 i = 5;

    IIC_HT_Init(); // I2C initialize

    while (i)
    {
        IIC_HT_Start(); // start I2C

        if (IIC_HT_Write_Byte(HTU20ADDR & 0xfe) == HTU20ACK) // I2C address + write
        {
            if (IIC_HT_Write_Byte(0xfe) == HTU20ACK) // soft reset
            {
                break;
            }
            else
            {
                i--;
            }
        }
        else
        {
            i--;
        }
    }

    IIC_HT_Stop(); // stop I2C
}

void SET_Resolution(void)
{
    IIC_HT_Start(); // Start I2C

    if (IIC_HT_Write_Byte(HTU20ADDR & 0xfe) == HTU20ACK) // I2C address + write + ACK
    {
        if (IIC_HT_Write_Byte(0xe6) == HTU20ACK)
        {
            if (IIC_HT_Write_Byte(0x83) == HTU20ACK)
            {
                ;
            }
        }
    }

    IIC_HT_Stop(); // Stop I2C
}

U8 crc_8(U8 *ptr, U8 len)
{
    U8 i;
    U8 crc = 0x00;

    while (len--)
    {
        crc ^= *ptr++;

        for (i = 8; i > 0; --i)
        {
            if (crc & 0x80)
            {
                crc = (crc << 1) ^ 0x31;
            }
            else
            {
                crc = (crc << 1);
            }
        }
    }

    return (crc);
}

void Readhtu20(void)
{
    U8 us_delay = 0, SHT_CRC = 0;
    U32 temp_value;

    static U8 tempData[3][2];
    static U8 humiData[3][2];

    static U8 count_humiErr;

    static U8 count_200ms = 0;
    static U8 whatdo = HTU20TEMP;

    if (count_200ms == 0)
    {
        count_200ms = 1;

        if (whatdo == HTU20TEMP)
        {
            whatdo = HTU20HUM;
        }
        else
        {
            whatdo = HTU20TEMP;
        }
    }
    else
    {
        count_200ms--;

        return;
    }

    SET_Resolution();

    IIC_HT_Start();

    while (IIC_HT_Write_Byte(HTU20ADDR & 0xfe) != HTU20ACK && us_delay < 40) // I2C address + write + ACK
    {
        delay_us(4);
        us_delay++;
    }

    if (us_delay >= 40)
    {
        count_humiErr++;
    }
    else
    {
        us_delay = 0;

        while (IIC_HT_Write_Byte(whatdo) != HTU20ACK && us_delay < 40) // Command
        {
            delay_us(4);
            us_delay++;
        }

        if (us_delay >= 40)
        {
            count_humiErr++;
        }
        else
        {
            us_delay = 0;

            do
            {
                delay_us(4);

                IIC_HT_Start();

                us_delay++;
            } while (IIC_HT_Write_Byte(HTU20ADDR | 0x01) == HTU20NACK && us_delay < 40); // I2C address + read + NACK

            if (us_delay >= 40)
            {
                count_humiErr++;
            }
            else
            {
                if (whatdo == HTU20HUM) // No Hold Master Mode，read humidity
                {
                    humiData[2][0] = humiData[1][0];
                    humiData[2][1] = humiData[1][1];

                    humiData[1][0] = humiData[0][0];
                    humiData[1][1] = humiData[0][1];

                    humiData[0][0] = IIC_HT_Read_Byte(HTU20ACK);
                    humiData[0][1] = IIC_HT_Read_Byte(HTU20ACK);

                    SHT_CRC = IIC_HT_Read_Byte(HTU20NACK); // Checksum  + NACK

                    IIC_HT_Stop(); // Stop I2C

                    if (crc_8(humiData, 2) != SHT_CRC)
                    {
                        count_humiErr++;

                        humiData[0][0] = humiData[1][0];
                        humiData[0][1] = humiData[1][1];

                        humiData[1][0] = humiData[2][0];
                        humiData[1][1] = humiData[2][1];

                        return;
                    }

                    f_htu20_Err = 0;
                    count_humiErr = 0;

                    temp_value = ((U32)humiData[0][0] << 8) + humiData[0][1];
                    temp_value += ((U32)humiData[1][0] << 8) + humiData[1][1];
                    temp_value += ((U32)humiData[2][0] << 8) + humiData[2][1];
                    temp_value = temp_value / 3;

                    temp_value = ((temp_value * 1250) / 65536) - 60;

                    htu20.hum = (U16)temp_value;

                    if (htu20.hum > 1000)
                    {
                        htu20.hum = 1000;
                    }
                }
                else if (whatdo == HTU20TEMP) // No Hold Master Mode，read temperature
                {
                    tempData[2][0] = tempData[1][0];
                    tempData[2][1] = tempData[1][1];

                    tempData[1][0] = tempData[0][0];
                    tempData[1][1] = tempData[0][1];

                    tempData[0][0] = IIC_HT_Read_Byte(HTU20ACK);
                    tempData[0][1] = IIC_HT_Read_Byte(HTU20ACK);

                    SHT_CRC = IIC_HT_Read_Byte(HTU20NACK); // Checksum  + NACK

                    IIC_HT_Stop(); // Stop I2C

                    if (crc_8(tempData, 2) != SHT_CRC)
                    {
                        count_humiErr++;

                        tempData[0][0] = tempData[1][0];
                        tempData[0][1] = tempData[1][1];

                        tempData[1][0] = tempData[2][0];
                        tempData[1][1] = tempData[2][1];

                        return;
                    }

                    f_htu20_Err = 0;
                    count_humiErr = 0;

                    temp_value = ((U32)tempData[0][0] << 8) + tempData[0][1];
                    temp_value += ((U32)tempData[1][0] << 8) + tempData[1][1];
                    temp_value += ((U32)tempData[2][0] << 8) + tempData[2][1];
                    temp_value = temp_value / 3;

                    temp_value = ((temp_value * 17572) / 65536 - 4685) / 10;

                    htu20.temp = (U16)temp_value;
                }
            }
        }
    }

    if (count_humiErr >= 10)
    {
        f_htu20_Err = 1;

        IIC_HT_Init();
        SoftReset();

        count_humiErr = 0;
    }
}
#endif
